<template>
  <div class="face-entry-container">
    <div class="header-margin">
      <el-page-header @back="goBack" content="上一级页面" />
    </div>
    <div class="main-content">
      <div class="example-section">
        <h4>正确示例（请参考地址）：</h4>
        <div @click="exampleHumanFace" class="example-link">人脸正确示例</div>
      </div>
      <div class="instruction-section">
        <div class="process-steps">
          <span class="step-item">开始录制</span> >
          <span class="step-item">录制中</span> >
          <span class="step-item">等待录入中</span> >
          <span class="step-item">完成</span>
        </div>
        <div class="instruction-text">
          <div class="instruction-paragraph">
            在录入人脸过程中，首先确保设备电量充足、摄像头清晰无遮挡，并选择光线适宜的环境。保持面部与摄像头平行，正视摄像头，避免夸张表情或头部晃动。
            注意衣着和发型不应遮挡面部特征。遵循系统提示的录入步骤，
            耐心完成操作。注意个人隐私保护，避免无关人员在场。
          </div>
          <div>
            <p class="error-title">常见错误及解决方案:</p>
            <p>
              <span class="error-text">无法检测到人脸：</span>将人脸靠近摄像头并保证无其他遮挡物挡住脸部。
            </p>
            <p>
              <span class="error-text">活体检测不通过：</span>在光线充足的地方将人脸靠近摄像头录入，必要时进行补光拍摄。
            </p>
          </div>
        </div>
      </div>
      <div class="user-icon">
        <div class="video-container">
          <video width="500" height="400" ref="videoDom" id="video" preload autoplay loop muted></video>
          <canvas width="500" height="385" ref="canvasDOM"></canvas>
        </div>
        <div class="button">
          <el-button type="primary" v-if="status===0" @click="initTracker()">
            <i class="el-icon-camera-solid"></i>&nbsp;开始录入
          </el-button>
          <el-button type="danger" v-else-if="status===1">
            <i class="el-icon-camera-solid icon-blink"></i>&nbsp;
            录制中
          </el-button>
          <el-button type="info" v-else-if="status===2">
            <i class="el-icon-camera-solid"></i>&nbsp;等待录入中
          </el-button>
          <el-button type="warning" v-else-if="status===3" @click="reEntry">
            <i class="el-icon-camera-solid"></i>&nbsp;重新录入
          </el-button>
        </div>
      </div>
    </div>

    <div align="center">{{loding}}</div>
  </div>
</template>

<script>
import service from "../../utils/request";

require("tracking/build/tracking-min.js");
require("tracking/build/data/face-min.js");
export default {
  name: "FaceLoginAli",
  data() {
    return {
      // 记录拍照到了几次
      count: 0,
      isdetected: "请您保持脸部在画面中央",
      loding: "",
      media: null,
      status: 0,
      opacityValue: 0, // 初始透明度为0,
      interval: null
    };
  },
  methods: {
    openMedia() {
      // 启用摄像头,这一个是原生调用摄像头的功能,不写的话有时候谷歌浏览器调用摄像头会失败
      navigator.mediaDevices
        .getUserMedia({ video: true, audio: true })
        .then(this.getMediaStreamSuccess)
        .catch(this.getMediaStreamError);
    },
    reEntry() {
      this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
      this.count = 0;
      this.openMedia();
      this.status = 1;
    },
    exampleHumanFace() {
      window.open(
        "https://www.yaoxuedao.com/template/college/face_requirements.html"
      );
    },
    // 初始化racker
    initTracker() {
      this.status = 1;
      this.context = this.canvas.getContext("2d");

      // 初始化tracking参数
      this.tracker = new tracking.ObjectTracker("face");
      this.tracker.setInitialScale(4);
      this.tracker.setStepSize(2);
      this.tracker.setEdgesDensity(0.1);
      this.tracker.on("track", event => {
        this.onTracked(event);
      });

      // tracking启用摄像头,这里我选择调用原生的摄像头
      // tracking.track(this.video, this.tracker, { camera: true });

      // 如果是读取视频，可以用trackerTask.stop trackerTask.run来暂停、开始视频
      this.trackerTask = tracking.track(this.video, this.tracker);
    },
    goBack() {
      this.onStopTracking();
      this.$router.back();
    },
    // 监听中
    onTracked(event) {
      // 判断终止条件, stop是异步的，不返回的话，还会一直截图
      if (this.count >= 21) {
        this.onStopTracking();
        return;
      }

      // 画框框
      this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
      event.data.forEach(rect => {
        this.context.lineWidth = 1;
        this.context.strokeStyle = "#a64ceb";
        //'#a64ceb';
        this.context.strokeRect(rect.x, rect.y, rect.width, rect.height);
        this.context.font = "11px Helvetica";
        this.context.fillStyle = "#fff";
        // 截图
        if (event.data.length > 0 && this.count <= 20) {
          if (this.count < 0) {
            this.count = 0;
          }
          this.count += 1;
          if (this.count > 20) {
            this.isdetected = "已检测到人脸，正在识别";
            this.status = 2;
            this.getPhoto();
          } else {
            this.isdetected = "请保持头部不动，正在检测";
          }
        } else {
          this.count -= 1;
          if (this.count < 0) {
            this.isdetected = "请您保持脸部在画面中央";
          }
        }
      });
      // 视频中心展示文字
      this.context.fillText(this.isdetected, 200, 50);
    },
    // 停止监听
    onStopTracking() {
      if (this.trackerTask) {
        this.trackerTask.stop();
      }
      this.video.pause();
      // 关闭摄像头
      this.video.srcObject = null;
      window.stream.getTracks().forEach(track => track.stop());
    },
    // 获取人脸照片
    getPhoto() {
      this.isdetected = "";
      this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
      let video = document.getElementById("video");
      this.context.drawImage(
        video,
        0,
        0,
        this.canvas.width,
        this.canvas.height
      );
      let dataUrl = this.canvas.toDataURL("image/jpeg", 1);
      this.imgbase64 = dataUrl.replace(/^data:image\/\w+;base64,/, "");
      // 开始人脸识别
      this.postFace();
    },
    // 人脸验证
    postFace() {
      service({
        method: "post",
        url: "/users/face/entry",
        timeout: 10 * 60 * 1000,
        data: { img: this.imgbase64 }
      })
        .then(res => {
          this.loding = "";
          if (res.flag) {
            this.$notify({
              title: "人脸录入",
              message: "人脸录入成功",
              type: "success"
            });
            this.goBack();
          } else {
            this.$notify({
              title: "人脸录入",
              message: "人脸录入失败",
              type: "error"
            });
            this.status = 3;
          }
        })
        .catch(() => {
          this.status = 3;
        });
    },
    // 视频流启动
    getMediaStreamSuccess(stream) {
      window.stream = stream;
      this.video.srcObject = stream;
    },
    // 视频媒体流失败
    getMediaStreamError(error) {
      this.$message.error("视频媒体流获取错误" + error);
    }
  },
  mounted() {
    this.video = this.$refs.videoDom;
    this.canvas = this.$refs.canvasDOM;

    this.openMedia();
  },
  beforeDestroy() {
    this.onStopTracking();
  }
};
</script>

<style scoped>
.user-icon {
  width: 500px;
  padding-top: 50px;
  padding-bottom: 30px;
  display: flex;
  flex-direction: column;
  margin-left: auto;
  margin-right: 70px;
}

.button {
  text-align: center;
  color: white;
}

video,
canvas {
  position: absolute;
}

@keyframes blink {
  0%,
  100% {
    opacity: 0;
  }
  50% {
    opacity: 1;
  }
}

.icon-blink {
  animation: blink 2s ease-in-out infinite;
}

/* 提取的内联样式 */
.face-entry-container {
  padding: 30px 20px 0 20px;
}

.header-margin {
  margin-bottom: 30px;
}

.main-content {
  display: flex;
  flex-direction: row;
  background-color: #f6f6f6;
}

.example-section {
  width: 300px;
  margin: 80px 0 0 60px;
}

.example-link {
  cursor: pointer;
  color: #409EFF;
}

.instruction-section {
  width: 360px;
  margin: 78px 0 0 100px;
}

.process-steps {
  color: #4f4f4f;
  font-weight: bold;
  text-align: center;
}

.step-item {
  margin: 0 5px;
}

.instruction-text {
  margin-top: 15px;
  color: #626262;
  font-size: 14px;
  line-height: 2rem;
}

.instruction-paragraph {
  text-indent: 2em;
}

.error-title {
  font-weight: bold;
}

.error-text {
  color: red;
}

.video-container {
  height: 400px;
  margin-right: 100px;
}
</style>
